<?php

// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------

/**
 * 系统公共库文件
 * 主要定义系统公共函数库
 */

/**
 * 字符串转换为数组，主要用于把分隔符调整到第二个参数
 * @param  string $str  要分割的字符串
 * @param  string $glue 分割符
 * @return array
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function str2arr($str, $glue = ',') {
    return explode($glue, $str);
}

/**
 * 数组转换为字符串，主要用于把分隔符调整到第二个参数
 * @param  array  $arr  要连接的数组
 * @param  string $glue 分割符
 * @return string
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function arr2str($arr, $glue = ',') {
    return implode($glue, $arr);
}

/**
 * 数据签名认证
 * @param  array  $data 被认证的数据
 * @return string       签名
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function data_auth_sign($data) {
    //数据类型检测
    if (!is_array($data)) {
        $data = (array) $data;
    }
    ksort($data); //排序
    $code = http_build_query($data); //url编码并生成query字符串
    $sign = sha1($code); //生成签名
    return $sign;
}

/**
 * 系统加密方法
 * @param string $data 要加密的字符串
 * @param string $key  加密密钥
 * @param int $expire  过期时间 单位 秒
 * @return string
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function think_encrypt($data, $key = '', $expire = 0) {
    $key = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
    $data = base64_encode($data);
    $x = 0;
    $len = strlen($data);
    $l = strlen($key);
    $char = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l)
            $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    $str = sprintf('%010d', $expire ? $expire + time() : 0);

    for ($i = 0; $i < $len; $i++) {
        $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
    }
    return str_replace('=', '', base64_encode($str));
}

/**
 * 系统解密方法
 * @param  string $data 要解密的字符串 （必须是think_encrypt方法加密的字符串）
 * @param  string $key  加密密钥
 * @return string
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function think_decrypt($data, $key = '') {
    $key = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
    $x = 0;
    $data = base64_decode($data);
    $expire = substr($data, 0, 10);
    $data = substr($data, 10);

    if ($expire > 0 && $expire < time()) {
        return '';
    }

    $len = strlen($data);
    $l = strlen($key);
    $char = $str = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l)
            $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    for ($i = 0; $i < $len; $i++) {
        if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
            $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
        } else {
            $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
        }
    }
    return base64_decode($str);
}

/**
 * 对查询结果集进行排序
 * @access public
 * @param array $list 查询结果
 * @param string $field 排序的字段名
 * @param array $sortby 排序类型
 * asc正向排序 desc逆向排序 nat自然排序
 * @return array
 */
function list_sort_by($list, $field, $sortby = 'asc') {
    if (is_array($list)) {
        $refer = $resultSet = array();
        foreach ($list as $i => $data)
            $refer[$i] = &$data[$field];
        switch ($sortby) {
            case 'asc': // 正向排序
                asort($refer);
                break;
            case 'desc':// 逆向排序
                arsort($refer);
                break;
            case 'nat': // 自然排序
                natcasesort($refer);
                break;
        }
        foreach ($refer as $key => $val)
            $resultSet[] = &$list[$key];
        return $resultSet;
    }
    return false;
}

/**
 * 把返回的数据集转换成Tree
 * @param array $list 要转换的数据集
 * @param string $pid parent标记字段
 * @param string $level level标记字段
 * @return array
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = '_child', $root = 0) {
    // 创建Tree
    $tree = array();
    if (is_array($list)) {
        // 创建基于主键的数组引用
        $refer = array();
        foreach ($list as $key => $data) {
            $refer[$data[$pk]] = & $list[$key];
        }
        foreach ($list as $key => $data) {
            // 判断是否存在parent
            $parentId = $data[$pid];
            if ($root == $parentId) {
                $tree[] = & $list[$key];
            } else {
                if (isset($refer[$parentId])) {
                    $parent = & $refer[$parentId];
                    $parent[$child][] = & $list[$key];
                }
            }
        }
    }
    return $tree;
}

/**
 * 将list_to_tree的树还原成列表
 * @param  array $tree  原来的树
 * @param  string $child 孩子节点的键
 * @param  string $order 排序显示的键，一般是主键 升序排列
 * @param  array  $list  过渡用的中间数组，
 * @return array        返回排过序的列表数组
 * @author yangweijie <yangweijiester@gmail.com>
 */
function tree_to_list($tree, $child = '_child', $order = 'id', &$list = array()) {
    if (is_array($tree)) {
        $refer = array();
        foreach ($tree as $key => $value) {
            $reffer = $value;
            if (isset($reffer[$child])) {
                unset($reffer[$child]);
                tree_to_list($value[$child], $child, $order, $list);
            }
            $list[] = $reffer;
        }
        $list = list_sort_by($list, $order, $sortby = 'asc');
    }
    return $list;
}

/**
 * 格式化字节大小
 * @param  number $size      字节数
 * @param  string $delimiter 数字和单位分隔符
 * @return string            格式化后的带单位的大小
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function format_bytes($size, $delimiter = '') {
    $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
    for ($i = 0; $size >= 1024 && $i < 5; $i++)
        $size /= 1024;
    return round($size, 2) . $delimiter . $units[$i];
}

/**
 * 设置跳转页面URL
 * 使用函数再次封装，方便以后选择不同的存储方式（目前使用cookie存储）
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function set_redirect_url($url) {
    cookie('redirect_url', $url);
}

/**
 * 获取跳转页面URL
 * @return string 跳转页URL
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function get_redirect_url() {
    $url = cookie('redirect_url');
    return empty($url) ? __APP__ : $url;
}

/**
 * 时间戳格式化
 * @param int $time
 * @return string 完整的时间显示
 * @author huajie <banhuajie@163.com>
 */
function time_format($time = NULL, $format = 'Y-m-d H:i') {
    $time = $time === NULL ? NOW_TIME : intval($time);
    return date($format, $time);
}

//基于数组创建目录和文件
function create_dir_or_files($files) {
    foreach ($files as $key => $value) {
        if (substr($value, -1) == '/') {
            mkdir($value);
        } else {
            @file_put_contents($value, '');
        }
    }
}

if (!function_exists('array_column')) {

    function array_column(array $input, $columnKey, $indexKey = null) {
        $result = array();
        if (null === $indexKey) {
            if (null === $columnKey) {
                $result = array_values($input);
            } else {
                foreach ($input as $row) {
                    $result[] = $row[$columnKey];
                }
            }
        } else {
            if (null === $columnKey) {
                foreach ($input as $row) {
                    $result[$row[$indexKey]] = $row;
                }
            } else {
                foreach ($input as $row) {
                    $result[$row[$indexKey]] = $row[$columnKey];
                }
            }
        }
        return $result;
    }

}

// =========================================================================================
// @author   sutroon <14507247@qq.com>
// @since 1.0 2014-6-24 by sutroon; 2.0 2014-12-22 by sutroon 重构函数命名,统一加前缀sofn_
// =========================================================================================
/**
 * 发送sokcet数据
 * @param string $in
 * @param string $ip
 * @param int $port
 * @return string
 * @since 1.0 2014-08-14 by kerry
 * @example socket_send($tsid . ',' . $state)
 */
function sofn_socket_send($in, $ip = '', $port = 8855) {
    if (!$ip) {
        $ip = $_SERVER['SERVER_NAME'];
    }
    error_reporting(E_ALL);
    set_time_limit(0);
    $fp = stream_socket_client("udp://$ip:$port", $errno, $errstr);
    // echo 'stream_socket_client("udp://'.$ip.':'.$port.'", $errno, $errstr)';
    if (!$fp) {
        return "ERROR: $errno - $errstr";
    } else {
        fwrite($fp, $in);
        return fread($fp, 26);
        fclose($fp);
    }
}

/**
 * 将参数转换成数组
 * @param $str 参数,如 a=1&b=2&c=3
 * @param string $col 列分隔符,如 =
 * @param string $row 行分隔符,如 &
 * @return array|false 返回拆分后的数组或false
 * @since 1.0 2014-10-29 by sutroon; 
 * @example 
 *      $arr=sofn_string_params_to_array('a=1&b=2&c=3');
 *      $arr_items = sofn_string_params_to_array($items, '=', ';');
 */
function sofn_string_params_to_array($str, $col = '=', $row = '&') {
    $arr = explode($row, $str);
    $arrOut = false;
    foreach ($arr as $item) {
        $arr2 = explode($col, $item);
        if (empty($arr2[0]) && $arr2[0] !== '0') {
            $arr2[0] = $arr2[1];
        }
        $arrOut[$arr2[0]] = $arr2[1];
    }
    return $arrOut;
}

/**
 * 合并数组为字符串
 * 
 * @param string $glue 合并符号
 * @param array $arr 数组
 * @param int $start 开始索引
 * @param int $end 结束索引
 * @return string
 * @since 1.0 2015-2-7 by sutroon
 * @example sofn_array_implode('|', $item, 4)
 */
function sofn_array_implode($glue, $arr, $start = 0, $end = 0) {
    if ($end > 0) {
        $len = count($arr);
        if ($end >= $len) {
            $end = $len - 1;
        }
    }
    if ($start > 0 && $end > 0 && $start > $end) {
        $start = $end;
    }
    $i = 0;
    $str = '';
    foreach ($arr as $key => $value) {
        if ($start > 0 && $i < $start) {
            $i++;
            continue;
        }
        if ($end > 0 && $i > $end) {
            break;
        }
        $str .= $glue . $value;
        $i++;
    }
    return $str ? substr($str, 1) : $str;
}

/**
 * 返回数组维数
 * @param array $arr
 * @return int mixed
 * @since 1.0 2014-10-21 by http://www.jbxue.com/article/13484.html
 * @example 
 *      sofn_array_level(array(0,1,2)); // 1
 *      sofn_array_level(array(array(0),array(1),array(2))); // 2
 *      sofn_array_level(array(0,array(0,array(1)))); // 3
 */
function sofn_array_level($arr) {
    $al = array(0);
    if (!function_exists('aL')) {

        function aL($arr, &$al, $level = 0) {
            if (is_array($arr)) {
                $level++;
                $al[] = $level;
                foreach ($arr as $v) {
                    aL($v, $al, $level);
                }
            }
        }

    }
    aL($arr, $al);
    return max($al);
}

/**
 * 遍历数组并检查数组中的元素是否包含在内容中
 * @param string $content
 * @param array $key_array
 * @param bool $key_is_content 是否把数组元素当内容(在数组元素中搜索内容),默认false
 * @return bool
 * @since 1.0 2014-12-22 by sutroon
 * @example $sop=sofn_array_key_contains(array('soc','zhan123'));
 */
function sofn_array_key_contains($content, $key_array, $key_is_content = false) {
    if (!is_array($key_array)) {
        return false;
    }
    if ($key_is_content) {
        foreach ($key_array as $k) {
            if (false === strpos($k, $content)) {
                continue;
            }
            return true;
        }
    } else {
        foreach ($key_array as $k) {
            if (false === strpos($content, $k)) {
                continue;
            }
            return true;
        }
    }
    return false;
}

/**
 * 判断是否为索引数组(没有键名)
 * @param array $array
 * @return bool
 * @since 1.0 2014-6-24 by sutroon
 * @example 
 *      sofn_is_assoc_array(array(0,1,2)) // false
 *      sofn_is_assoc_array(array('a'=>1,'b'=>2)) // true
 */
function sofn_is_assoc_array($array) {
    return array_keys($array) !== range(0, count($array) - 1);
}

/**
 * 检测字符串是否已指定的字符串开头
 * @param string $str
 * @param string $search
 * @return bool
 * @since 1.0.0 2013-10-7 sutroon
 * @example sofn_start_with('this is my words','th');
 */
function sofn_start_with($str, $search) {
    if (strlen($str) < strlen($search)) { //若第一个字符串长度小于第二个的时候，必须指定返回false，
        return false; //否则substr_compare遇到这种情况会返回0（即相当，与事实不符合）
    } else {
        return !substr_compare($str, $search, 0, strlen($search)); //当第一个长度大于第二个时才开始判断
    }
}

/**
 * 检测字符串是否已指定的字符串结尾
 * @param string $str 要查找的源字符串
 * @param string $search 关键词
 * @param bool $case_insensitivity 是否忽略大小写区别(默认不忽略)
 * @return bool
 * @example sofn_end_with('my words','ds');
 * @since
 *      1.0.1 2014-9-1 by sutroon 新增$case_insensitivity参数
 *      1.0.0 2013-10-7 by sutroon 创建
 */
function sofn_end_with($str, $search, $case_insensitivity = false) {
    if (strlen($str) < strlen($search)) { //若第一个字符串长度小于第二个的时候，必须指定返回false，
        return false; //否则substr_compare遇到这种情况会返回0（即相当，与事实不符合）
    } else {
        return !substr_compare($str, $search, strlen($str) - strlen($search), strlen($search), $case_insensitivity); //从第一个字符串减去第二个字符串长度处开始判断
    }
}

/**
 * 过滤前缀
 * @param string $str
 * @param string $trim
 * @return string
 * @since 1.0 2014-8-25 by sutroon
 * @example trim_start('00.100.00','00.')
 */
function sofn_trim_start($str, $trim) {
    $lentrim = strlen($trim);
    if (strlen($str) < $lentrim) {
        return $str;
    }
    if (substr($str, 0, $lentrim) == $trim) {
        return substr($str, $lentrim);
    }
    return $str;
}

/**
 * 过滤后缀
 * @param string $str
 * @param string $trim
 * @return string
 * @since 1.0 2014-8-25 by sutroon
 * @example trim_end('00.100.00','.00')
 */
function sofn_trim_end($str, $trim) {
    $lentrim = strlen($trim);
    $lenstr = strlen($str);
    if ($lenstr < $lentrim) {
        return $str;
    }
    if (substr($str, $lenstr - $lentrim) == $trim) {
        return substr($str, 0, $lenstr - $lentrim);
    }
    return $str;
}

/**
 * 将秒钟数格式化为时分秒的时间
 * @param int $seconds 秒钟数
 * @return string 时分秒时间格式
 * @since 1.0 2014-9-12 by sutroon
 * @example sofn_seconds_format(61) // 00:01:01
 */
function sofn_seconds_format($seconds) {
    if (!$seconds) {
        return '0:0:0';
    }
    $h = intval($seconds / 3600);
    $m = intval(($seconds % 3600) / 60);
    $s = $seconds % 60;
    return "$h:$m:$s";
}

/**
 * 时间轴开发，即显示为“刚刚”、“5分钟前”、“昨天10:23”等
 * @param string $time
 * @return string
 * @since 1.0.0 2013-5-4 sutroon
 * @example sofn_tran_time('2013-5-4 13:23:33');
 */
function sofn_tran_time($time) {
    if (!is_numeric($time)) {
        $time = strtotime($time);
    }
    $rtime = date("m-d H:i", $time);
    $htime = date("H:i", $time);
    $time = time() - $time;
    if ($time < 60) {
        $str = '刚刚';
    } elseif ($time < 60 * 60) {
        $min = floor($time / 60);
        $str = $min . '分钟前';
    } elseif ($time < 60 * 60 * 24) {
        $h = floor($time / (60 * 60));
        $str = $h . '小时前 ' . $htime;
    } elseif ($time < 60 * 60 * 24 * 3) {
        $d = floor($time / (60 * 60 * 24));
        if ($d == 1) {
            $str = '昨天 ' . $rtime;
        } else {
            $str = '前天 ' . $rtime;
        }
    } else {
        $str = $rtime;
    }
    return $str;
}

/**
 * 强制弹出保存文件对话框
 * @param string $default_file_name 对话框中默认文件名
 * @param string $content 要保存的内容
 * @param bool $is_path 指示$content参数是内容还是文件路径,默认false
 * @since 1.0 2014-10-11 by sutroon; 1.1 2015-1-5 by sutroon 新增路径支持功能
 * @example sofn_save_file_dialog('image1.jpg',file_get_contents($path));
 */
function sofn_save_file_dialog($default_file_name, $content, $is_path = false) {
    if ($is_path) {
        if (file_exists($content)) {
            //打开文件  
            $file = fopen($content, "r");
            //输入文件标签   
            Header("Content-type: application/octet-stream");
            Header("Accept-Ranges: bytes");
            Header("Accept-Length: " . filesize($content));
            Header("Content-Disposition: attachment; filename=" . $default_file_name);
            //读取文件内容并直接输出到浏览器  
            echo fread($file, filesize($content));
            fclose($file);
            exit();
        } else {
            die('抱歉, 服务器上文件已删除或更名, 请联系管理员!');
        }
    } else {
        if (false === $content) {
            die('抱歉, 服务器上文件已删除或更名, 请联系管理员!');
        }
        header("Content-Type: application/force-download");
        header('Content-Disposition: attachment; filename="' . $default_file_name . '"');
        echo $content;
        exit(0);
    }
}

/**
 * 导出Excel
 * @param array $list 数据集
 * @param array $options 更多选项,包含 string:FILENAME, string:SHEETNAME, int:ActiveSheet
 * @since 1.0 2014-9-5 by sutroon
 * @since 1.1 <2015-4-10> SoChishun 修正导出大数值自动变为科学计数的问题
 * @example sofn_excel_export($list);
 */
function sofn_excel_export($list, $options = array()) {
    $options = array_merge(array('FILENAME' => 'EXCEL-' . now('Ymd-His'), 'SHEETNAME' => 'Sheet1', 'ActiveSheet' => 0), is_array($options) ? $options : array());
    vendor('PHPExcel.PHPExcel');
    $objPHPExcel = new PHPExcel();
    $objPHPExcel->getProperties()->setCreator("XCall")
            ->setLastModifiedBy("PHPExcel")
            ->setTitle("Office 2007 XLSX Test Document")
            ->setSubject("Office 2007 XLSX Test Document")
            ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.")
            ->setKeywords("office 2007 openxml php")
            ->setCategory("Test result file");
    $sheet = $objPHPExcel->getActiveSheet($options['ActiveSheet']);
    $i = 1;
    foreach ($list as $row) {
        if ($i == 1) {
            $c = 0;
            foreach ($row as $k => $v) {
                $sheet->setCellValueByColumnAndRow($c, $i, $k);
                $c++;
            }
        }
        $i++;
        $c = 0;
        foreach ($row as $k => $v) {
            //$sheet->setCellValueByColumnAndRow($c, $i, $v);
            $sheet->setCellValueExplicitByColumnAndRow($c, $i, $v, PHPExcel_Cell_DataType::TYPE_STRING);
            $c++;
        }
    }
    $objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddHeader('&L&G&C&HPlease treat this document as confidential!');
    $objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddFooter('&L&B' . $objPHPExcel->getProperties()->getTitle() . '&RPage &P of &N');
    $objPHPExcel->getActiveSheet()->setTitle($options['SHEETNAME']);
    $filename = $options['FILENAME'] . '.xlsx';
    $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
    header('Content-Type: application/vnd.ms-excel');
    header("Content-Disposition: attachment;filename=$filename");
    header('Cache-Control: max-age=0');
    $objWriter->save('php://output');
    exit(0);
}

/**
 * 将Excel文件转为数组
 * @param string $path Excel文件的服务器路径
 * @param array $options 更多选项,包含 int:START, int:COUNT, int:ActiveSheet
 * @return mixed 如果文件存在则返回array,否则返回false
 * @since 1.0 2014-9-5 by sutroon
 * @example $arr_content = sofn_excel_import(UPLOAD_ROOT . $msg['filePath']);
 */
function sofn_excel_import($path, $options = array()) {
    $options = array_merge(array('START' => 1, 'COUNT' => 0, 'ActiveSheet' => 0), is_array($options) ? $options : array());
    if (!file_exists($path)) {
        return false;
    }
    vendor('PHPExcel.PHPExcel');
    $objPHPExcel = PHPExcel_IOFactory::load($path);
    $sheet = $objPHPExcel->getActiveSheet($options['ActiveSheet']);
    $highestRow = $sheet->getHighestRow(); // 取得总行数,数值,如:30
    $highestColumnName = $sheet->getHighestColumn(); // 取得总列数,字符,如:F
    $highestColumn = PHPExcel_Cell::columnIndexFromString($highestColumnName); // 转换成数值
    $arr = array();
    $i = $options['START'] + 1; // 从第2行开始才是数据行,第一行是标题栏
    $count = $options['COUNT'];
    while ($i <= $highestRow) {
        if ($count > 0) {
            if (($i - 2) > $count) {
                break;
            }
        }
        for ($c = 0; $c < $highestColumn; $c++) {
            $cell = $sheet->getCellByColumnAndRow($c, $i);
            $value = $cell->getValue();
            if ($value instanceof PHPExcel_RichText) {
                //富文本转换字符串  
                $value = $value->__toString();
            }
            if ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_NUMERIC) {
                // 格式化日期
                $cellstyleformat = $cell->getStyle()->getNumberFormat();
                $formatcode = $cellstyleformat->getFormatCode();
                if (preg_match('/^(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy]/i', $formatcode)) {
                    $value = gmdate("Y-m-d", PHPExcel_Shared_Date::ExcelToPHP($value));
                } else {
                    $value = PHPExcel_Style_NumberFormat::toFormattedString($value, $formatcode);
                }
            }
            $key = $sheet->getCellByColumnAndRow($c, 1)->getValue();
            if ($key instanceof PHPExcel_RichText) {
                //富文本转换字符串  
                $key = $key->__toString();
            }
            $arr[$i - 2][$key] = $value;
        }
        $i++;
    }
    return $arr;
}

/**
 * 更新iptable
 * <br />如：update_iptables(get_client_ip());
 * <br />update_iptables('udp:5060','upd:5666');
 * @param string|int $value
 * @param string|int $oldvalue
 * @param string $filename
 * @param bool $restart
 * @return string|true 成功返回true，否则返回错误字符串
 * @since 1.0 2015-1-27 by sutroon
 */
function sofn_update_iptables($value, $oldvalue = 0, $filename = '/etc/sysconfig/iptables', $restart = FALSE) {
    if (!is_file($filename)) {
        return 'E_FILE_NO_FOUND';
    }
    $data = file_get_contents($filename);
    $keyword = '-A INPUT -j DROP';
    $pos = strpos($data, $keyword);
    if (false === $pos) {
        $keyword = 'COMMIT';
        $pos = strpos($data, $keyword);
        if (false === $pos) {
            return 'E_FILE_FORMAT';
        }
    }
    $iprule_old = false;
    if (false === strpos($value, '.')) {
        if ($oldvalue) {
            $arrValue = false === strpos($oldvalue, ':') ? array('tcp', $oldvalue) : explode(':', $oldvalue);
            $iprule_old = '-A INPUT -p ' . $arrValue[0] . ' -m udp --dport ' . $arrValue[1] . ' -j ACCEPT';
        }
        $arrValue = false === strpos($value, ':') ? array('tcp', $value) : explode(':', $value);
        $iprule = '-A INPUT -p ' . $arrValue[0] . ' -m udp --dport ' . $arrValue[1] . ' -j ACCEPT';
    } else {
        $iprule = "-A INPUT -s $value/255.255.255.255 -j ACCEPT";
    }
    if ($iprule_old) {
        if (false === strpos($data, $iprule_old)) {
            if (false === strpos($data, $iprule)) {
                $data = substr($data, 0, $pos) . $iprule . PHP_EOL . substr($data, $pos);
            }
        } else {
            $data = str_replace($iprule_old, $iprule, $data);
        }
    } else {
        if (false === strpos($data, $iprule)) {
            $data = substr($data, 0, $pos) . $iprule . PHP_EOL . substr($data, $pos);
        } else {
            return 'E_EXISTS';
        }
    }
    file_put_contents($filename, $data);
    if ($restart) {
        sleep(1);
        if (false === system("sudo /sbin/service iptables restart", $code)) {
            die($code);
        }
    }
    return true;
}

/**
 * 获取目录最后节点名称
 * @param string $path 路径名称
 * @return string
 * @since 1.0 2014-6-24 by sutroon
 * @example $lastdir = sofn_get_last_dir_name(dirname($path));
 */
function sofn_get_last_dir_name($path) {
    return substr($path, strrpos($path, '/') + 1);
}

/**
 * 获取文件后缀名(不带点号)
 * @param string $path
 * @return string
 * @since 1.0 2014-6-24 by sutroon
 * @example $ext = sofn_get_file_ext($path);
 */
function sofn_get_file_ext($path) {
    if (false !== ($pos = strrpos($path, '.'))) {
        return substr($path, $pos + 1);
    }
    return '';
}

/**
 * 更改文件后缀
 * @param $path 文件名称
 * @param $ext 后缀名称
 * @return string 更改后的新文件名
 * @since 1.0 2014-9-23 by sutroon
 * @example sofn_change_file_ext($path,'wav');
 */
function sofn_change_file_ext($path, $ext) {
    if (!$path || strpos($path, '.') === false) {
        return $path;
    }
    return substr($path, 0, strrpos($path, '.') + 1) . $ext;
}

/**
 * 循环删除目录和文件函数  
 * @param string $dirName 目录路径
 * @return false|array 返回不能删除的目录名称
 * @since 1.0 2015-1-20 http://blog.csdn.net/china_skag/article/details/7423559
 */
function sofn_del_dirAndFile($dirName) {
    $unlinks = false;
    if ($handle = opendir("$dirName")) {
        while (false !== ( $item = readdir($handle) )) {
            if ($item != "." && $item != "..") {
                if (is_dir("$dirName/$item")) {
                    $unlinks = $unlinks + sofn_del_dirAndFile("$dirName/$item");
                } else {
                    if (!unlink("$dirName/$item"))
                        $unlinks[] = $item;
                }
            }
        }
        closedir($handle);
        if (!rmdir($dirName)) {
            $unlinks[] = $dirName;
        }
    }
    return $unlinks;
}

/**
 * 删除目录下的文件
 * @param string $dirName 目录路径
 * @return false|array 返回不能删除的目录名称
 * @since 1.0 2015-1-20 http://blog.csdn.net/china_skag/article/details/7423559
 */
function sofn_del_fileUnderDir($dirName) {
    $unlinks = false;
    if ($handle = opendir("$dirName")) {
        while (false !== ( $item = readdir($handle) )) {
            if ($item != "." && $item != "..") {
                if (is_dir("$dirName/$item")) {
                    $unlinks = $unlinks + sofn_del_fileUnderDir("$dirName/$item");
                } else {
                    if (!unlink("$dirName/$item"))
                        $unlinks[] = $item;
                }
            }
        }
        closedir($handle);
    }
    return $unlinks;
}

/**
 * 过滤上传文件中的无效文件
 * @param array|false $emptys 无效文件名数组
 * @param array $files 文件,一般是$_FILES
 * @return array 返回过滤后的有效文件数组
 * @since 1.0 <2015-3-27> SoChishun Added.
 */
function sofn_file_filter(&$emptys, $files = '') {
    if ('' === $files) {
        $files = $_FILES;
    }
    $emptys = false;
    foreach ($files as $name => $file) {
        if ($file['error'] > 0) {
            $emptys[] = $name;
        }
    }
    if ($emptys) {
        foreach ($emptys as $name) {
            unset($files[$name]);
        }
    }
    return $files;
}

/**
 * 上传文件
 * @param array $options 选项 array('savePath' => '', 'saveName' => array('uniqid', ''), 'exts' => array('gif', 'jpg', 'jpeg', 'bmp', 'png'), 'maxSize' => 0, 'replace' => false,'skipEmpty' => true)
 * @param array $files 文件,如果为''则默认为$_FILES
 * @return string|array 返回错误字符串或上传后的文件信息数组,filepath是文件保存的具体路径
 * @since 1.0 <2015-3-27> SoChishun Added.
 * @example
 *      $files=  sofn_file_filter($emptys,$_FILES);
  $info = $files ? sofn_file_upload(array(), $files) : '没有需要上传的文件';
 */
function sofn_file_upload($options = array(), $files = '') {
    // 过滤空文件
    if (isset($options['skipEmpty'])) {
        if ($options['skipEmpty']) {
            $files = sofn_file_filter($emptys, $files);
            if (!$files) {
                return '没有文件被上传!';
            }
        }
        unset($options['skipEmpty']);
    }
    $rootPath = './Uploads/';
    $config = array(
        'mimes' => array(), //允许上传的文件MiMe类型
        'maxSize' => 0, //上传的文件大小限制 (0-不做限制)
        'exts' => array('gif', 'jpg', 'jpeg', 'bmp', 'png'), //允许上传的文件后缀
        'autoSub' => true, //自动子目录保存文件
        'subName' => array('date', 'Y-m-d'), //子目录创建方式，[0]-函数名，[1]-参数，多个参数使用数组
        'rootPath' => $rootPath, //保存根路径
        'savePath' => '', //保存路径,如 Images/或Faces/
        'saveName' => array('uniqid', ''), //上传文件命名规则，[0]-函数名，[1]-参数，多个参数使用数组, 空数组表示保持原名
        'saveExt' => '', //文件保存后缀，空则使用原后缀
        'replace' => false, //存在同名是否覆盖,false则提示存在同名文件
        'hash' => false, //是否生成hash编码
    );
    $config = array_merge($config, $options);
    is_dir($rootPath) || mkdir($rootPath); // 自动创建上传根目录
    $uploader = new \Think\Upload($config);
    $infos = $uploader->upload($files);
    if ($uploader->getError()) {
        return $uploader->getError();
    }
    // 新增一个filepath合成路径
    $returns = array();
    foreach ($infos as $key => $file) {
        $file['filepath'] = '/Uploads/' . $file['savepath'] . $file['savename'];
        $returns[$key] = $file;
    }
    return $returns;
}

/**
 * 非空字符串
 * 用默认值替代空字符串
 * @param string $val
 * @param mixed $defv
 * @return mixed
 * @since 1.0 2014-11-7 by sutroon
 * @example sofn_not_empty('','Default');
 */
function sofn_not_empty($val, $defv) {
    return (strlen($val) < 1) ? $defv : $val;
}

/**
 * 通用获取状态名称方法
 * @param string $v 值
 * @param string $type 类型
 *      yesno=否|是,activate=未激活|已激活,approval=未审核|已审核,startstop=已停止|已启动|已暂停,enable=已禁用|已启用,login:登出|登入,user=正常|待审核|禁用,sex=女士|先生|保密,marital=未婚|已婚|保密
 * @return string
 * @since 1.0 2014-7-7 by sutroon, 2014-12-3 新增$undefined
 * @example {$vo.state|sofn_get_state_text=user,###}
 */
function sofn_get_state_text($type, $v, $undefined = null) {
    switch (strtolower($type)) {
        case 'user-state':
            switch ($v) {
                case '1':
                    return '正常';
                case '0':
                    return '待审核';
                case '3':
                    return '冻结';
                case '4':
                    return '禁用';
                case '7':
                    return '注销';
                case '14':
                    return '回收站';
            }
            break;
        case 'start-stop':
            switch ($v) {
                case '0':
                    return '已停止';
                case '1':
                    return '已启动';
                case '2':
                    return '已暂停';
            }
            break;
        case 'activate-state':
            switch ($v) {
                case '0':
                    return '未激活';
                case '1':
                    return '已激活';
            }
            break;
        case 'yes-no':
            switch ($v) {
                case '0':
                case '':
                    return '否';
                case '1':
                    return '是';
            }
            break;
        case 'success-fail':
            switch ($v) {
                case '0':
                    return '失败';
                case '1':
                    return '成功';
            }
            break;
        case 'display-hide':
            switch ($v) {
                case '0':
                    return '隐藏';
                case '1':
                    return '显示';
            }
            break;
        case 'approval-state':
            switch ($v) {
                case '0':
                    return '未审核';
                case '1':
                    return '已审核';
            }
            break;
        case 'enable':
            switch ($v) {
                case '0':
                    return '已禁用';
                case '1':
                    return '已启用';
            }
            break;
        case 'login':
            switch ($v) {
                case '0':
                    return '已登出';
                case '1':
                    return '已登入';
            }
            break;
        case 'sex':
            switch ($v) {
                case '0':
                    return '女士';
                case '1':
                    return '先生';
                case '2':
                    return '保密';
            }
            break;
        case 'marital':
            switch ($v) {
                case '0':
                    return '未婚';
                case '1':
                    return '已婚';
                case '2':
                    return '保密';
            }
            break;
        case 'cti-call-result':
            switch ($v) {
                case 'ANSWERED':
                    return '应答';
                case 'NO ANSWER':
                    return '无应答';
                case 'CONGESTION':
                    return '堵塞';
                case 'BUSY':
                    return '忙音';
                case 'FAILED':
                    return '失败';
            }
            break;
        case 'cti-channel-state':
            switch ($v) {
                case '0':
                    return '空闲';
                case '1':
                    return '正在呼叫';
                case '2':
                    return '通话中';
                case '3':
                    return '呼叫成功';
                case '4':
                    return '呼叫失败';
            }
            break;
        case 'message-send-state':
            switch ($v) {
                case '0':
                    return '未发送';
                case '1':
                    return '发送成功';
                case '2':
                    return '发送失败';
            }
            break;
        case 'record-source':
            switch ($v) {
                case 'import':
                    return '导入';
                case 'add':
                    return '添加';
                case 'generate':
                    return '生成';
            }
            break;
        case 'pay-type':
            switch ($v) {
                case '0':
                    return '后付费';
                case '1':
                    return '预付费';
            }
            break;
        case 'settlement-status':
            switch ($v) {
                case '0':
                    return '未结算';
                case '1':
                    return '已结清';
                case '2':
                    return '部分结算';
            }
            break;
        case 'confirm':
            switch ($v) {
                case '0':
                    return '未审核';
                case '1':
                    return '审核通过';
                case '4':
                    return '审核拒绝';
            }
            break;
        case 'input-type':
            switch ($v) {
                case 'text':
                    return '单行文本框';
                case 'date':
                    return '日期';
                case 'datetime':
                    return '日期和时间';
                case 'time':
                    return '时间';
                case 'select':
                    return '下拉选择框';
                case 'radio':
                    return '单选框';
                case 'checkbox':
                    return '复选框';
                case 'textarea':
                    return '多行文本框';
                case 'editor':
                    return '可视化编辑器';
                case 'file':
                    return '文件上传框';
            }
            break;
        case 'cti-call-forwarding-type':
            switch ($v) {
                case '1':
                    return '无条件转接';
                case '2':
                    return '忙时转移';
                case '3':
                    return '无应答或不可用时转移';
                case '0':
                    return '';
            }
            break;
        case 'product-sale-state': // 商品销售状态
            switch ($v) {
                case '0':
                    return '下架';
                case '1':
                    return '上架';
            }
            break;
        case 'product-operate-type': // 商品进销存操作类型 2014-12-23 by sutroon
            switch ($v) {
                case 'SELL-RETURN':
                    return '销售退货(入库)';
                case 'SALE':
                    return '销售出库';
                case 'PURCHASE':
                    return '采购入库';
                case 'INTERNAL':
                    return '内部出库';
                case 'INVENTORY':
                    return '盘点调仓';
            }
            break;
        case 'customer-appointment-state': // 客户预约状态 2014-12-24 by sutroon
            switch ($v) {
                case '0':
                    return '未回访';
                case '1':
                    return '回访成功';
                case '2':
                    return '回访失败';
                case '4':
                    return '放弃回访';
            }
            break;
        case 'customer-appointment-source': // 客户预约来源 2014-12-24 by sutroon
            switch ($v) {
                case 'USER':
                    return '自定义';
                case 'ORDER':
                    return '订单回访';
            }
            break;
        case 'customer-buy-interested': // 客户购买意向 2014-12-25 by sutroon
            switch ($v) {
                case '0':
                    return '普通';
                case '1':
                    return '意向购买';
                case '2':
                    return '非常兴趣';
            }
            break;
    }
    return is_null($undefined) ? "未知[$type]" : $undefined;
}

/**
 * 获取存储过程标准返回值描述
 * @param int $code 返回代码
 * @param array $arr_msg 覆盖的描述
 * @return string 代码对应的描述
 * @since 1.0 2014-10-16 by sutroon
 * @example sofn_get_procedure_result_text($result['@oint_result'],array('1'=>'注册成功,请重新登录','4300'=>'手机号码已存在'));
 */
function sofn_get_procedure_result_text($code, $arr_msg = array()) {
    $arr_msg = $arr_msg + array(1 => '执行成功', 4000 => '系统错误', 4100 => '参数错误', 4200 => '状态有误', 4300 => '记录已存在', 4400 => '记录不存在', 4500 => '值不在范围内(小于下限或大于上限)');
    return array_key_exists($code, $arr_msg) ? $arr_msg[$code] : '未知错误' . $code;
}

/**
 * 判断是否手机端访问
 * @staticvar string $mobilebrowser_list
 * @return bool
 * @since 1.0 2014-12-9 http://www.thinkphp.cn/topic/8081.html
 */
function isMobile() {
    $mobile = array();
    static $mobilebrowser_list = 'Mobile|iPhone|Android|WAP|NetFront|JAVA|OperasMini|UCWEB|WindowssCE|Symbian|Series|webOS|SonyEricsson|Sony|BlackBerry|Cellphone|dopod|Nokia|samsung|PalmSource|Xphone|Xda|Smartphone|PIEPlus|MEIZU|MIDP|CLDC';
//note 获取手机浏览器
    if (preg_match("/$mobilebrowser_list/i", $_SERVER['HTTP_USER_AGENT'], $mobile)) {
        return true;
    } else {
        if (preg_match('/(mozilla|chrome|safari|opera|m3gate|winwap|openwave)/i', $_SERVER['HTTP_USER_AGENT'])) {
            return false;
        } else {
            if ($_GET['mobile'] === 'yes') {
                return true;
            } else {
                return false;
            }
        }
    }
}

/**
 * 设置图片
 * @param string $url 图片路径
 * @param string $folder 上传目录
 * @since 1.0 2014-12-29 by sutroon
 */
function sofn_set_image($url, $folder = '') {
    echo $url ? "<a href='$url' title='$url' target='_blank'><img src='$url' alt='$url' /></a>" : $url;
}

/**
 * 检测用户是否登录
 * @return mixed false-未登录，array-当前登录用户信息
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function sofn_get_login_data($sesnId) {
    $user = session($sid);
    if (empty($user)) {
        return FALSE;
    } else {
        return session('user_auth_sign') == data_auth_sign($user) ? $user : 0;
    }
}

function sofn_get_permission_rules($roleId) {
    
}

/**
 * 更新登录信息
 * @param $data
 * @since 1.0 2014-9-28 by sutroon
 * @example sofn_update_loginData(array('pageSize'=>$pageSize));
 */
function sofn_update_loginData($data) {
    $this->loginData = array_merge($this->loginData, $data);
    session(C('USR_SESSION_ID'), $this->loginData);
}

/**
 * 检测用户权限
 * @param string $key 权限关键词,如 add-user,edit-user,delete-user, 客户管理,新增客户,删除客户等
 * @param bool $end 无权限时是否终止输出,默认true
 * @param array $upr 用户权限数据
 * @return bool
 * @since 1.0 2014-12-29 by sutroon
 * @example 
 *  $this->sofn_check_upr('客户管理');
 *  if (!$this->sofn_check_upr('删除客户', false)) {
 *      $this->act_ajaxReturn(false, '没有权限!');
 *  }
 */
function sofn_check_upr($key, $end = true, $upr = array()) {
    if (!$upr) {
        $upr = $this->UPR;
    }
    if (!$upr || !isset($upr[$key]) || !$upr[$key]) {
        if ($end) {
            die("没有权限!");
        }
        return false;
    }
    return true;
}

/**
 * 返回项目的AppData目录<br />包含Conf、Template、TempSqls等
 * @param array $options 选项,包含siteID, userID, type, subdir选项
 * @return string 返回路径地址
 * @since 1.0 2015-1-19 by sutroon
 * @example
 * sofn_get_appdata_dir(array('siteID'=>$this->loginData['siteID'],'userID'=>$this->loginData['id'],'type'=>'TempSqls','subdir'=>'CustomerImp')).date('Ymdhis').'.sql'; // 获取sql临时文件目录
 * sofn_get_appdata_dir(array('type'=>'Template')).'customer_import_file.xlsx'; // 获取模板文件
 * sofn_get_appdate_dir(array('type'=>'Conf')).'AppConf.conf'; // 获取配置文件
 */
function sofn_get_appdata_dir($options) {
    if (!$options || !is_array($options)) {
        return APP_ROOT_PATH . 'AppData/';
    }
    $dirs[] = 'AppData';
    $arrData = array('conf' => 'Conf', 'tempsqls' => 'TempSqls', 'template' => 'Template');
    if (isset($options['type'])) {
        $options['type'] = strtolower($options['type']);
        if (array_key_exists($options['type'], $arrData)) {
            $dirs[] = $arrData[$options['type']];
        }
    }
    if (isset($options['subdir'])) {
        $dirs[] = $options['subdir'];
    }
    $name = '';
    if (isset($options['siteID'])) {
        $name.='S' . $options['siteID'];
    }
    if (isset($options['userID'])) {
        $name.='U' . $options['userID'];
    }
    if ($name) {
        $dirs[] = $name;
    }
    $path = APP_ROOT_PATH . implode('/', $dirs);
    if (!is_dir($path)) {
        mkdir($path, 0777, true);
    }
    return ($path[strlen($path)] == '/') ? $path : $path . '/';
}

/**
 * 检测权限是否存在
 * @param string $code 权限代码
 * @param int $uid 用户编号
 * @return bool
 * @since 1.0 2014-7-24 by sutroon
 * @example sofn_equal_permission('YH_YGGL', $this->loginData['id'])
 */
function sofn_equal_permission($code, $uid) {
    $cache_id = 'userPermissionRule' . $uid;
    $str = S($cache_id);
    if (!$str) {
        $str = M('tuser')->where("id=$uid")->getField('permissionRule');
        S($cache_id, $str, array('expire' => 30));
    }
    if (!$str) {
        return false;
    }
    $ruleID = M('tuser_permission')->where("code='$code'")->getField('id');
    if (!$ruleID) {
        return false;
    }
    if (false === strpos(",$str,", ",$ruleID,")) {
        return false;
    }
    return true;
}

/**
 * 获取订单状态描述
 * @param string $target, 流程主体,如:xcallcrm
 * @param int $val 状态值
 * @return string
 * @since 1.0 2015-1-9 by sutroon
 * @example sofn_get_order_state_text('xcallcrm',0);
 */
function sofn_get_order_state_text($type, $val) {
    $arr_states = array('0' => '未审核', '1' => '交易完成', '20' => '核单通过', '24' => '核单失败', '30' => '已发货', '未签收', '34' => '仓库退回', '40' => '座席取消', '41' => '买家取消', '42' => '逾期取消', '43' => '订单无效取消', '50' => '客户签收', '54' => '客户拒签', '55' => '客户退货');
    return array_key_exists($val, $arr_states) ? $arr_states[$val] : "未知[$val]";
}

/**
 * 生成序列号(支持10亿以下不重复序号)
 * 规则：[前缀][siteID1|9]0[userID1|9][timestamp14]
 * 生成位数：17-33
 * @param string $prefix 前缀,DD=订单,KH=客户,CZ=充值
 * @param int $siteID
 * @param int $uid
 * @return string
 * @since 1.0 2014-1-9 by sutroon
 */
function sofn_get_serial_no($prefix, $siteID, $uid) {
    return $prefix . $siteID . '0' . $uid . date('Ymdhis');
}

/**
 * 字符串截取，支持中文和其他编码
 * @param string $str 需要转换的字符串
 * @param string $start 开始位置
 * @param string $length 截取长度 默认null
 * @param string $charset 编码格式 默认utf-8
 * @param string $suffix 截断显示字符 默认false
 * @return string
 * @since 1.0 <2015-4-3> SoChishun Refactoring by \Org\Util\String::msubstr
 */
function sofn_msubstr($str, $start = 0, $length = NULL, $charset = "utf-8", $suffix = false) {
    if (function_exists("mb_substr"))
        $slice = mb_substr($str, $start, is_null($length) ? mb_strlen($str, $charset) - $start : $length, $charset);
    elseif (function_exists('iconv_substr')) {
        $slice = iconv_substr($str, $start, is_null($length) ? iconv_strlen($str, $charset) - $start : $length, $charset);
    } else {
        $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
        $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
        $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
        $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
        preg_match_all($re[$charset], $str, $match);
        $slice = join("", array_slice($match[0], $start, $length));
    }
    return $suffix ? $slice . '...' : $slice;
}
